﻿using System;
using System.Drawing;
using System.Windows.Forms;
using Marmat.Foundation;
using Marmat.FrameWork;
using DevExpress.Utils.Menu;
using DevExpress.XtraEditors;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;

namespace Marmat.Template.WinForm
{
    /// <summary>
    /// 编辑窗体的默认实现。
    /// </summary>
    public partial class EditForm : Marmat.Forms.Form, Marmat.Foundation.IEditForm
    {

        readonly Pen pen = new(Color.FromArgb(191, 191, 191));
        readonly List<IEditFormPanel> panelCollection = new();
        private bool _panel2Visible;
        private bool _panel3Visible;

        private bool panel2Visible
        {
            get => _panel2Visible;
            set
            {
                _panel2Visible = value;
                this.panel2.Visible = value;
            }
        }
        private bool panel3Visible
        {
            get => _panel3Visible;
            set
            {
                _panel3Visible = value;
                this.panel3.Visible = value;
            }
        }

        /// <summary>
        /// 构建默认的编辑窗体。
        /// </summary>
        public EditForm()
        {
            InitializeComponent();

            this.editButton.Text = Localization.EditForm.EditButtonCaption;
            this.createButton.Text = Localization.EditForm.CreateButtonCaption;
            this.saveButton.Text = Localization.EditForm.SaveButtonCaption;
            this.cancelButton.Text = Localization.EditForm.CancelButtonCaption;
            this.dropDownButton1.Text = Localization.EditForm.PrintButtonCaption;
            this.dropDownButton2.Text = Localization.EditForm.ActionButtonCaption;
            this.panel2.Visible = panel2Visible;
            this.panel3.Visible = panel3Visible;
        }

        //private void EditForm_Load(object sender, EventArgs e)
        //{
        //    var controller = this.editRoute.GetController();
        //    if (controller != null)
        //    {
        //        if (controller.Id is null && controller.Id.Equals(string.Empty))
        //            controller.CreateDataObject();
        //        else
        //            controller.LoadDataObject();
        //    }
        //}

        #region 属性

        /// <summary>
        /// 编辑路由
        /// </summary>
        private IEditFormRoute editRoute;
        private System.Windows.Forms.Control control;

        #endregion

        /// <summary>
        /// 点击下拉按钮时打开属于该按钮的下拉列表
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DropDownButton1_Click(object sender, EventArgs e)
        {
            if (sender is Control control)
            {
                control.BringToFront();
            }
            this.dropDownButton1.BringToFront();
            DropDownButton dropDown = (DropDownButton)sender;
            dropDown.ShowDropDown();
        }

        /// <summary>
        /// 执行控制器的创建方法
        /// </summary>
        public void Create()
        {
            if (this.editRoute.GetController() is IEditFormCreateController controller)
                controller.Create();
            else
            {
                this.editRoute.GetController().CreateDataObject();
                this.Editor();
            }
        }

        /// <summary>
        /// 删除
        /// </summary>
        public virtual void Delete()
        {
            IEditFormController controller = this.editRoute.GetController();
            if (controller.Id == null)
                throw new ArgumentNullException(nameof(controller.Id));
            controller.Delete();
            this.Close();
        }

#pragma warning disable IDE1006 // 命名样式
        /// <summary>
        /// 放弃修改
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void simpleButton3_Click(object sender, EventArgs e)
        {
            this.RejectChanges();
        }

        /// <summary>
        /// 保存
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void simpleButton4_Click(object sender, EventArgs e)
        {
            this.Save();
        }

        /// <summary>
        /// 创建
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnCreate_Click(object sender, EventArgs e)
        {
            if (createButton.Name == "createButton")
                this.Create();
            else if (createButton.Name == "closeButton")
                this.Close();
        }

        /// <summary>
        /// 编辑
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void simpleButton1_Click(object sender, EventArgs e)
        {
            IEditFormController controller = this.editRoute.GetController();
            if (controller.AllowEdit)
            {
                this.Editor();
            }
        }

        #region IFormEditorStyle 接口
        /// <summary>
        /// 开启预览模式
        /// </summary>
        public virtual void Preview()
        {
            IEditFormController controller = this.editRoute.GetController();
            if (controller is IEditFormEditorStyle editor)
            {
                try
                {
                    Marmat.Forms.WindowsAPI.LockWindowUpdate(this.Handle.ToInt32());
                    this.panel2Visible = true;
                    this.panel3Visible = false;
                    this.tableLayoutPanel1.Visible = true;
                    is_editor = false;
                    editor.Preview();
                }
                finally
                {
                    Marmat.Forms.WindowsAPI.LockWindowUpdate(IntPtr.Zero.ToInt32());
                }
            }
        }

        /// <summary>
        /// 是否属于编辑状态
        /// </summary>
        private bool is_editor = false;

        /// <summary>
        /// 开启编辑模式
        /// </summary>
        public virtual void Editor()
        {
            IEditFormController controller = this.editRoute.GetController();
            if (controller is IEditFormEditorStyle editor)
            {
                Marmat.Forms.WindowsAPI.LockWindowUpdate(this.Handle.ToInt32());
                try
                {
                    editor.Editor();
                    is_editor = true;
                    this.panel2Visible = false;
                    this.panel3Visible = true;
                    this.tableLayoutPanel1.Visible = false;
                    editRoute.GetDataPanel().Focus();
                }
                catch (Exception ex)
                {
                    Marmat.Forms.MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                finally
                {
                    Marmat.Forms.WindowsAPI.LockWindowUpdate(IntPtr.Zero.ToInt32());
                }
            }
        }

        #endregion

        /// <summary>
        /// 动态布局编辑和创建按钮的ui位置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void EditButton_VisibleChanged(object sender, EventArgs e)
        {
            int left = 12;
            if (this.editButton.Visible == true)
            {
                this.editButton.Left = left;
                left += this.editButton.Width + 6;
            }
            if (this.createButton.Visible == true)
                this.createButton.Left = left;
        }

        private void Panel1_Paint(object sender, PaintEventArgs e)
        {
            Control control = (Control)sender;
            e.Graphics.DrawLine(pen, 0, control.Height - 1, control.Width, control.Height - 1);
        }

        /// <summary>
        /// 点击保存时执行,保存成功后会重新刷新数据
        /// </summary>
        /// <returns>返回true，则代表执行了保存操作(不代表执行成功)</returns>
        public virtual bool Save()
        {
            return this.Save(true);
        }
        /// <summary>
        /// 点击保存时执行
        /// </summary>
        /// <param name="refreshData">保存成功后是否重新刷新数据。</param>
        /// <returns>返回true，则代表执行了保存操作(不代表执行成功)</returns>
        public virtual bool Save(bool refreshData)
        {
            bool result = false;
            this.OnValidated(EventArgs.Empty);
            IEditFormController controller = this.editRoute.GetController();
            if (controller.Id is null || string.IsNullOrEmpty(controller.Id.ToString()) || controller.HasChanges())
            {
                if (!controller.Verify())
                    return result;
                controller.Save();
                result = true;
            }
            if (this.IsDisposed || this.control.Disposing || this.control.IsDisposed)
                return result;

            if (controller is IEditFormEditorStyle)
            {
                this.Preview();
                if (this.dropDownButton2.DropDownControl is DXPopupMenu dXPopup)
                {
                    this.dropDownButton2.Visible = controller.Id != null && dXPopup.Items.Count > 0;
                }
            }
            else if (controller is IEditFormCustomSaveSucceed customSaveSucceed)
            {
                customSaveSucceed.Successful();
            }
            else
            {
                if (this.Modal)
                    this.DialogResult = DialogResult.OK;
                else
                    this.Close();
            }
            if (result)
            {
                IAlert alert = SystemCommand.GetService<IAlert>();
                if (alert is not null)
                    alert.Show("保存成功", AlertTypeEeum.Success);
                if (refreshData && !string.IsNullOrEmpty(controller.Id?.ToString()))
                    controller.LoadDataObject();
            }
            return result;
        }

        /// <summary>
        /// 撤消
        /// </summary>
        public virtual void RejectChanges()
        {
            this.OnValidated(EventArgs.Empty);
            IEditFormController controller = this.editRoute.GetController();

            if (!this.editRoute.GetDataPanel().IsDisposed && controller.HasChanges())
                if (Marmat.Forms.MessageBox.Show("记录已被修改，您的更改将被丢弃。 你想继续吗？", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.Cancel)
                    return;
            is_editor = false;
            //如果当前单据是新增或者没有实现 IEditFormEditorStyle 接口，取消则直接退出页面,否则撤回修改,并修改为预览模式
            if (controller.Id == null || controller is IEditFormEditorStyle == false)
                this.Close();
            else
            {
                controller.RejectChanges();
                if (this.IsDisposed == false)
                    this.Preview();
            }
        }


        /// <summary>
        /// 设置控制器
        /// </summary>
        /// <param name="controller"></param>
        public void SetController(IEditFormController controller)
        {
            if (controller is Control == false)
                throw new Exception($"{nameof(controller)} 必须 继承于 System.Windows.Forms.Control。");
            if (controller is Control control)
            {
                IEditFormRoute route = new DefaultEditFormRoute(controller, control);
                SetRoute(route);
            }
        }

        /// <summary>
        /// 设置路由
        /// </summary>
        /// <param name="route"></param>
        public void SetRoute(IEditFormRoute route)
        {
            this.editRoute = route;
            Control control = this.editRoute.GetDataPanel();
            IEditFormController controller = this.editRoute.GetController();

            controller.EditForm = this;
            controller.StatusChanged += this.StatusChanged;

            bool visible = true;
            if (controller is IEditFormEditorStyle)
            {
                if (controller is IEditFormCreateController createEdit)
                    this.createButton.Visible = createEdit.AllowCreate;
                else
                {
                    this.createButton.Name = "closeButton";
                    this.createButton.Visible = true;
                    this.createButton.ImageOptions.Image = Properties.Resources.cancel_icon;
                    this.createButton.Text = "关闭";
                }
                this.editButton.Visible = controller.AllowEdit;
                if (controller.Id is null)
                    this.Editor();
                else
                    this.Preview();
            }
            else
            {
                //如果未实现IFormEditorStyle接口则不显示创建与编辑按钮
                Marmat.Forms.WindowsAPI.LockWindowUpdate(this.Handle.ToInt32());
                this.panel2Visible = false;
                this.panel3Visible = controller.AllowEdit;
                this.panel1.Visible = controller.AllowEdit;
                visible = controller.AllowEdit;
                Marmat.Forms.WindowsAPI.LockWindowUpdate(IntPtr.Zero.ToInt32());
            }

            control.Disposed += this.Control_Disposed;
            control.TextChanged += this.Control_TextChanged;
            this.Size = new Size(control.ClientSize.Width + (this.Width - this.ClientSize.Width), control.ClientSize.Height + (this.Height - this.ClientSize.Height) + (visible ? panel1.Height : 0));
            if (control is System.Windows.Forms.Form frm)
            {
                this.Icon = frm.Icon;
                this.ControlBox = frm.ControlBox;
                this.ShowIcon = frm.ShowIcon;
                this.MinimizeBox = frm.MinimizeBox;
                this.MaximizeBox = frm.MaximizeBox;
                this.ShowInTaskbar = frm.ShowInTaskbar;
                this.SizeGripStyle = frm.SizeGripStyle;
                this.TopMost = frm.TopMost;
                this.TransparencyKey = frm.TransparencyKey;
                this.Opacity = frm.Opacity;
                this.StartPosition = frm.StartPosition;
                this.WindowState = frm.WindowState;
                this.FormBorderStyle = frm.FormBorderStyle;

                frm.TopLevel = false;
                frm.Parent = this;
                frm.WindowState = FormWindowState.Normal;
                frm.FormBorderStyle = FormBorderStyle.None;
                frm.Show();
            }

            if (this.control != null)
                this.Controls.Remove(this.control);
            this.Text = control.Text;
            this.control = control;
            this.panelControl.Controls.Add(control);

            #region 添加扩展面板
            if (controller is IEditFormPanelCollection editFormPanelCollection)
                this.panelCollection.AddRange(editFormPanelCollection.GetPanelCollection());
            this.panelCollection.AddRange(SystemCommand.GetServices<IEditFormPanel>());
            if (panelCollection.Count > 0)
            {
                control.Dock = DockStyle.Fill;
                IEditFormPanelContainer panelContainer = SystemCommand.GetService<IEditFormPanelContainer>();
                if (panelContainer is not null)
                {
                    panelContainer.Builder(this.panelControl, controller, panelCollection);
                    if (panelContainer is System.Windows.Forms.Control container)
                        this.panelControl.Controls.Add(container);
                }
            }
            else
                control.Dock = DockStyle.Fill;
            #endregion

            control.BringToFront();
            control.Select();
            this.StatusChanged(this, EventArgs.Empty);
        }

        /// <summary>
        /// 状态变更时触发的事件。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void StatusChanged(object sender, EventArgs e)
        {
            var controller = this.editRoute.GetController();
            this.panel3.Visible = this.panel3Visible && controller.AllowEdit;//设置是否显示编辑按钮。
            this.editButton.Visible = controller.AllowEdit;
            // 更新动作集合及打印集合
            bool loadButtonVisible = false;
            bool printButtonVisible = false;
            bool actionButtonVisible = false;
            bool actionButtonEnabled = false;
            // 如果id不为空的情况下，根据规则显示动作及打印按钮。
            if (controller.Id != null && !string.IsNullOrEmpty(controller.Id?.ToString()))
            {
                #region 更新动作集合
                List<(IButtonItem, Action)> actionCollection = new List<(IButtonItem, Action)>();

                // 增加删除动作
                ButtonItem _deleteButton = new("删除");
                _deleteButton.Enabled = controller.AllowDelete;
                _deleteButton.Icon = Properties.Resources.delete_icon;
                actionCollection.Add((_deleteButton, () =>
                {
                    if (MessageBox.Show("你确定要删除此记录吗？", "确认", MessageBoxButtons.OKCancel, MessageBoxIcon.Information) == DialogResult.OK)
                        this.Delete();
                }
                ));

                //增加复制动作
                if (controller is IEditFormCopy copy)
                {
                    bool allow = true;
                    if (controller is IEditFormCreateController createController && createController.AllowCreate == false)
                        allow = false;
                    if (allow)
                    {
                        ButtonItem button = new ButtonItem("复制");
                        button.Icon = Properties.Resources.copy_icon;
                        actionCollection.Add((button, () => copy.Copy()));
                    }
                }

                //根据接口约定配置动作列表

                if (controller is IAction action)
                {
                    var items = action.GetActionCollection();
                    if (items != null)
                    {
                        foreach (var item in items)
                        {
                            actionCollection.Add((item, () => action.Execute(item)));
                        }
                    }
                }

                // 根据特性动态配置动作列表。
                var methods = controller.GetType().GetMethods().ToList();
                methods.ForEach(method =>
                {
                    var actionAttribute = method.GetCustomAttribute<Marmat.Foundation.ActionAttribute>();
                    if (actionAttribute is not null && method.GetParameters().Length == 0)
                    {
                        bool is_permission = true;
                        foreach (var attribute in method.GetCustomAttributes())
                        {
                            if (attribute is IPermissionAttribute permission)
                            {
                                if (!permission.Verify())
                                {
                                    is_permission = false;
                                    break;
                                }
                            }
                        }
                        if (is_permission)
                        {
                            ButtonItem item = new (actionAttribute.Name, actionAttribute.Text);
                            actionCollection.Add((item, () => method.Invoke(controller, null)));
                        }
                    }
                });

                if (this.dropDownButton2.DropDownControl is null)
                    this.dropDownButton2.DropDownControl = new DXPopupMenu();
                if (this.dropDownButton2.DropDownControl is DXPopupMenu dropDownControl)
                {
                    dropDownControl.Items.Clear();
                    foreach (var pair in actionCollection)
                    {
                        var item = pair.Item1;
                        DXMenuItem button = new DXMenuItem();
                        button.Caption = string.IsNullOrEmpty(item.Caption) ? item.Name : item.Caption;
                        button.Enabled = item.Enabled;
                        if (item.Icon != null)
                            button.ImageOptions.Image = item.Icon;
                        button.Click += delegate (object _, EventArgs __) { pair.Item2.Invoke(); };
                        dropDownControl.Items.Add(button);
                    }
                }
                loadButtonVisible = true;
                actionButtonVisible = actionCollection.Count > 0;
                actionButtonEnabled = actionCollection.Select(x => x.Item1).ToList().Exists(x => x.Enabled);
                #endregion

                #region 配置打印集合
                List<(IButtonItem, Func<IReportObject>)> reportCollection = new List<(IButtonItem, Func<IReportObject>)>();
                if (controller is IReport report)
                {
                    foreach (var item in report.GetReportCollection())
                    {
                        reportCollection.Add((item, () =>
                        {
                            IReportObject reportObject = Marmat.FrameWork.SystemCommand.GetService<IReportObject>();
                            if (reportObject is null)
                                throw new NotImplementedException($"没有检测到 {typeof(Marmat.Foundation.IReportObject).FullName} 服务。");
                            reportObject.Load(item.Name);
                            Marmat.Foundation.ReportCancelEventArgs args = new ReportCancelEventArgs(reportObject);
                            report.Print(args);
                            if (args.Cancel)
                                reportObject = null;
                            return reportObject;
                        }
                        ));
                    }
                }
                methods.ForEach(method =>
                {
                    var reportAttribute = method.GetCustomAttribute<Marmat.Foundation.ReportAttribute>();
                    var parameters = method.GetParameters();
                    if (reportAttribute is not null && (parameters.Length == 0 || (parameters.Length == 1 && parameters[0].ParameterType == typeof(IReportObject))))
                    {
                        var permissionAttribute = method.GetCustomAttribute<Marmat.Template.WinForm.PermissionAttribute>();
                        IPermission permission = Marmat.FrameWork.SystemCommand.GetService<IPermission>();
                        if (permissionAttribute is null || permission is null || permission.Verify(permissionAttribute.permission_Id))
                        {
                            ButtonItem item = new ButtonItem(reportAttribute.Name, reportAttribute.Text);
                            reportCollection.Add((item, () =>
                            {
                                object[] arguments = null;
                                IReportObject tmp = null;
                                if (parameters.Length == 1 && parameters[0].ParameterType == typeof(IReportObject))
                                {
                                    tmp = Marmat.FrameWork.SystemCommand.GetService<IReportObject>();
                                    tmp.Load(item.Name);
                                    arguments = new object[] { tmp };
                                }
                                var returnValue = method.Invoke(controller, arguments);
                                if (returnValue is IReportObject reportObject)
                                    tmp = reportObject;
                                return tmp;
                            }
                            ));
                        }
                    }
                });

                var reportDesignSupport = SystemCommand.GetService<IReportDesignSupport>();
                if (reportCollection.Count > 0 && reportDesignSupport?.AllowDesign() == true)
                {
                    ButtonItem item = new ButtonItem("设计", "设计", Properties.Resources.design_icon);
                    reportCollection.Add((item, () =>
                    {
                        EditFormReportCollection frm = new EditFormReportCollection(reportCollection.Where(x => x.Item1 != item).ToList());
                        frm.ShowDialog();
                        return null;
                    }
                    ));
                }
                if (this.dropDownButton1.DropDownControl is null)
                    this.dropDownButton1.DropDownControl = new DXPopupMenu();
                if (this.dropDownButton1.DropDownControl is DXPopupMenu dropDownl)
                {
                    dropDownl.Items.Clear();
                    foreach (var pair in reportCollection)
                    {
                        var item = pair.Item1;
                        DXMenuItem button = new DXMenuItem();
                        button.Caption = string.IsNullOrEmpty(item.Caption) ? item.Name : item.Caption;
                        button.Enabled = item.Enabled;
                        if (item.Icon != null)
                            button.ImageOptions.Image = item.Icon;
                        button.Click += delegate (object _, EventArgs _)
                        {
                            var reportObject = pair.Item2.Invoke();
                            reportObject?.Prepare();
                        };
                        dropDownl.Items.Add(button);
                    }
                }
                printButtonVisible = reportCollection.Count > 0;
                #endregion
            }

            //设置工具栏一直显示。
            this.loadButton.Visible = loadButtonVisible;
            this.dropDownButton1.Visible = printButtonVisible;
            this.dropDownButton2.Enabled = actionButtonEnabled;
            this.dropDownButton2.Visible = actionButtonVisible;
            this.panel1.Visible = true;


            foreach (var panel in this.panelCollection)
            {
                panel?.Load(controller);
            }
        }

        private void Control_TextChanged(object sender, EventArgs e)
        {
            this.Text = this.editRoute.GetDataPanel().Text;
        }

        private void Control_Disposed(object sender, EventArgs e)
        {
            this.Close();
        }

        private void EditForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            var panel = this.editRoute.GetDataPanel();
            var controller = this.editRoute.GetController();
            if (is_editor && !panel.IsDisposed && (controller.Id is null || controller.HasChanges()))
            {
                if (Marmat.Forms.MessageBox.Show("记录已被修改，您的更改将被丢弃。 你想继续吗？", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.Cancel)
                    e.Cancel = true;
            }
        }

        /// <summary>
        /// 刷新表单
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void loadButton_Click(object sender, EventArgs e)
        {
            try
            {
                this.loadButton.Enabled = false;
                this.OnValidated(EventArgs.Empty);
                var controller = this.editRoute.GetController();
                IAlert alert = SystemCommand.GetService<IAlert>();
                if (!controller.HasChanges())
                {
                    controller.LoadDataObject();
                    if (alert is not null)
                        alert.Show("刷新成功", AlertTypeEeum.Success);
                }
                else
                {
                    if (alert is not null)
                        alert.Show("请先保存已修改的数据再刷新。", AlertTypeEeum.Warning);
                }
            }
            finally
            {
                this.loadButton.Enabled = true;
            }
        }

        private void EditForm_Load(object sender, EventArgs e)
        {
            this.Invalidate();
        }
    }
}
